package com.jsti.ccp.error.handler;

import com.google.gson.Gson;
import com.jsti.ccp.common.result.FeignResult;
import com.jsti.ccp.error.annotations.TicFeignController;
import com.jsti.ccp.error.constants.CcpExceptionConstant;
import com.jsti.ccp.error.exception.TicRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

/**
 * 通用的网关接口异常处理器
 **/
@Slf4j
@Component
@RestControllerAdvice(annotations = {TicFeignController.class})
public class FeignExceptionHandler {
    
    private Gson gson = new Gson();


    /**
     * 参数校验异常处理
     *
     * @param exception {@link MethodArgumentNotValidException} 参数异常
     * @return 响应结果
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    public FeignResult<?> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) {
        log.error("Feign MethodArgumentNotValidException:", exception);
        BindingResult result = exception.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            errors.forEach(p -> {
                FieldError fieldError = (FieldError) p;
                stringBuilder.append(fieldError.getDefaultMessage());
            });
        }
        return getFeignFailedResult(CcpExceptionConstant.SERVICE_ERROR_CODE, stringBuilder.toString());
    }

    /**
     * 业务校验异常处理
     *
     * @param exception {@link IllegalArgumentException} 校验异常
     * @return 响应结果
     */
    @ExceptionHandler(value = IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.OK)
    public FeignResult<?> illegalArgumentExceptionHandler(IllegalArgumentException exception) {
        log.error("Feign IllegalArgumentException:", exception);
        String message = exception.getMessage();
        try {
            /*兼容断言形式用message设置messageCode操作*/
            Integer messageCode = Integer.valueOf(message);
            return getFeignFailedResult(messageCode, message);
        } catch (Exception e) {
            /*三方组件直接抛出异常*/
            return getFeignFailedResult(CcpExceptionConstant.SERVICE_ERROR_CODE, e.getMessage());
        }
    }

    /**
     * RuntimeException异常处理
     *
     * @param exception {@link RuntimeException} 运行时异常
     * @return 响应结果
     */
    @ExceptionHandler(value = {RuntimeException.class})
    @ResponseStatus(HttpStatus.OK)
    public FeignResult<?> runtimeExceptionHandler(RuntimeException exception) {
        log.error("Feign RuntimeException:", exception);
        return getFeignFailedResult(CcpExceptionConstant.SERVICE_ERROR_CODE, gson.toJson(exception.toString()));
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.OK)
    public FeignResult<?> exceptionHandler(Exception exception) {
        log.error("Feign Exception:", exception);
        return getFeignFailedResult(CcpExceptionConstant.SERVICE_ERROR_CODE,  gson.toJson(exception.toString()));
    }


    @ExceptionHandler(value = TicRuntimeException.class)
    @ResponseStatus(HttpStatus.OK)
    public FeignResult<?> TicRuntimeExceptionHandler(TicRuntimeException exception) {
        log.error("Feign TicRuntimeException:", exception);
        return getFeignFailedResult(exception.getCode(), exception.getMessage());
    }

    private FeignResult getFeignFailedResult(Integer code, String message) {
        return new FeignResult(code, message);
    }
}
